﻿using LightSO.ILibrary;
using LightSO.ILibrary.Mapping;
using ServiceStack.Redis;
using ServiceStack.Redis.Generic;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LightSO.Library.Redis
{
    /// <summary>
    /// Rides数据仓储上下文类
    /// </summary>
    /// <author>linlurui</author>
    /// <typeparam name="T">实体类</typeparam>
    internal class DbContext<T> : IDisposable where T : class
    {
        static readonly object lockObj = new object();
        static Dictionary<string, int> dict = new Dictionary<string, int>();
        static Dictionary<string, DbContext<T>> _instants = new Dictionary<string, DbContext<T>>();

        public IRedisClient Database { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public DbContext()
        {
            string[] connStringRead = ConfigurationManager.ConnectionStrings["redisconnread"].ConnectionString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            string[] connStringWrite = ConfigurationManager.ConnectionStrings["redisconnwrite"].ConnectionString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            var manage = new PooledRedisClientManager(connStringRead, connStringWrite, new RedisClientManagerConfig
            {
                MaxWritePoolSize = 1000,//“写”链接池链接数
                MaxReadPoolSize = 1000,//“读”链接池链接数
                AutoStart = true,
                DefaultDb = 8 //默认数据库
            });

            Database = manage.GetClient();
        }
        public DbContext(string connString)
        {
            Database = new RedisClient(connString);
        }

        /// <summary>
        /// Redis中的客服端对象
        /// </summary>
        internal IRedisList<T> GetCollection(string collectionName = "")
        {
            IRedisTypedClient<T> typed = Database.As<T>();

            if (string.IsNullOrWhiteSpace(collectionName))
            {
                collectionName = GetCollectionName();
            }


            try
            {
                var dbIndex = Convert.ToInt32(DB);

                Database.Db = dbIndex;
            }
            catch
            {
                return null;
            }

            var table = typed.Lists[collectionName];


            return table;
        }

        internal static string GetCollectionName()
        {
            var _att = Attribute.GetCustomAttribute(typeof(T), typeof(RedisIdAttribute));
            string _collectionName = _att != null ? ((RedisIdAttribute)_att).Name : typeof(T).Name;

            if (string.IsNullOrEmpty(_collectionName))
            {
                throw new ArgumentException("Collection name cannot be empty for this entity");
            }

            Regex reg = new Regex(@"({Date\(([\d\w\-\. :]+)\)})");
            if (reg.Match(_collectionName).Groups.Count > 2 &&
                reg.Match(_collectionName).Groups[2].Success)
            {
                var format = reg.Match(_collectionName).Groups[1].Value;

                _collectionName = reg.Replace(_collectionName, DateTime.Now.ToString(format));
            }

            return _collectionName;
        }

        private static DbContext<T> Create(string connectionName)
        {
            lock (lockObj)
            {
                DbContext<T> _db;
                if (!_instants.TryGetValue(connectionName, out _db))
                {
                    _db = new DbContext<T>(connectionName);
                    _instants.Add(connectionName, _db);
                }
                return _db;
            }

        }
        /// <summary>
        /// 获取数据库名称
        /// </summary>
        private static int DB
        {
            get
            {
                var classFullName = typeof(T).FullName;
                if (!dict.ContainsKey(classFullName))
                {
                    lock (lockObj)
                    {
                        if (!dict.ContainsKey(classFullName))
                        {
                            dict[classFullName] = 0;

                            var customAttributes = typeof(T).GetCustomAttributes(false);
                            foreach (var item in customAttributes)
                            {
                                if (item is RedisDataSource)
                                {
                                    RedisDataSource customDataAttribute = item as RedisDataSource;
                                    dict[classFullName] = customDataAttribute.DB;

                                    break;
                                }
                            }
                        }
                    }
                }

                return dict[classFullName];
            }
        }


        #region Dispose
        private bool _disposed;

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool _disposing)
        {
            if (!_disposed)
            {
                if (_disposing)
                {
                    //cleanup managed resources

                    GC.SuppressFinalize(this);
                }

                //cleanup unmanaged resources

                _disposed = true;
            }
        }

        #endregion
    }
}
